#!/bin/bash
#
# Flash FPGA program to spi flash
#
# Copyright 2020 Tronlong Elec. Tech. Co. Ltd. All Rights Reserved.

#################################################
## PC16         --> FPGA_DONE         80       ##
## PC5          --> OE pin            69       ##
## PC4          --> FPGA_PROG         68       ##
#################################################

################ GPIO index #####################
## gpio index = (bank - 1) * 32 + gpio bit     ##
## example: PC5 index = (3 - 1) * 32 + 5 ##
fpga_done_pin=80
spi_oe_pin=69
fpga_prog=68
#################################################

# Help message.
function usage() {
    echo "
    Usage: $0 <binfile>

    options:
        binfile:    bin file to write
    e.g.
        $0 /root/led_flash_pgl25g.sfc
    "
}

# Set program pin level state
function set_fpga_program_pin(){

    if [ ! -d "/sys/class/gpio/gpio$fpga_prog" ];then
        echo $fpga_prog > /sys/class/gpio/export
    fi    
    # programm pin output low
    if [ $1 -eq 0 ]; then
        echo out > /sys/class/gpio/gpio$fpga_prog/direction
        echo 0 > /sys/class/gpio/gpio$fpga_prog/value
        sleep 1
    # programm pin output high
    elif [ $1 -eq 1 ];then
        echo out > /sys/class/gpio/gpio$fpga_prog/direction
        echo 1 > /sys/class/gpio/gpio$fpga_prog/value
        sleep 1
    fi
}

# Set OE pin level state
function set_spi_oe_pin() {
    if [ ! -d "/sys/class/gpio/gpio$spi_oe_pin" ];then
        echo $spi_oe_pin > /sys/class/gpio/export
    fi

    echo out > /sys/class/gpio/gpio$spi_oe_pin/direction
    echo $1 > /sys/class/gpio/gpio$spi_oe_pin/value
}

# Mount FPGA spi flash
function mount_spi_fpga_flash() {
    lsmod | grep m25p80 >> /dev/null
    if [ $? -eq 0 ]; then
        rmmod mtd.ko
        rmmod m25p80.ko
    fi

    # Connect arm spi interface to spi fpga flash
    set_spi_oe_pin 1

    # Register the spi flash
    insmod mtd.ko
    insmod m25p80.ko
}

# Umount FPGA spi flash
function umount_spi_fpga_flash() {
    rmmod m25p80.ko
    rmmod mtd.ko

    # Disconnect arm spi interface to spi fpga flash
    set_spi_oe_pin 0
    sleep 1
}

# Flash FPGA program to spi flash
function flash_spiflash() {
    flash_erase /dev/mtd0 0 0
    dd if=$1 of=/dev/mtd0
}

# Get the done pin status
function get_done_pin_state() {
    local state

    if [ ! -d "/sys/class/gpio/gpio$fpga_done_pin" ];then
        echo $fpga_done_pin > /sys/class/gpio/export
    fi

    echo in > /sys/class/gpio/gpio$fpga_done_pin/direction

    state=$(cat /sys/class/gpio/gpio$fpga_done_pin/value)

    echo $state
}

######### MAIN ENTRANCE #########
function main() {
    local state

    case $1 in
        -h)
            usage
            exit 0
            ;;
        -v)
            echo "Version: flash_fpga_${MAJOR_VERSION/\./}_${MINOR_VERSION/\./}"
            exit 0
            ;;
    esac

    if [ $# != 1 ]; then
        usage
        exit 1
    fi

    # 1. Reset to configuration logic
    echo -e "\n1/6:"
    echo "Reset to configuration logic"
    set_fpga_program_pin 0

    # 2. Mount FPGA spiflash
    echo -e "\n2/6:"
    echo "Mount FPGA spi flash"
    mount_spi_fpga_flash

    # 3. Flash the FPGA app to spi flash
    echo -e "\n3/6:"
    echo "Flash FPGA program to spi flash"
    flash_spiflash $1
    if [[ $? -eq 1 ]]; then
        echo "Flash FPGA program to spi flash failed."
        umount_spi_fpga_flash
        exit 1
    fi

    # 4. UMount FPGA spiflash
    echo -e "\n4/6:"
    echo "UMount FPGA spi flash"
    umount_spi_fpga_flash

    # 5. Reload FPGA program
    echo -e "\n5/6:"
    echo "FPGA reload app"
    set_fpga_program_pin 0
    sleep 1
    set_fpga_program_pin 1

    # 6. Wait fpga config done
    echo -e "\n6/6:"
    echo "Wait fpga config done"
    loop_count=0
    while [ $loop_count -le 32 ];
    do
        # get the fpga done pin state
        state=$(get_done_pin_state)
        if [ $state -eq 1 ]; then
            echo "FPGA reload app succeeded."
            exit 0
        fi

        sleep 1
        loop_count=$((loop_count + 1))
    done

    echo "FPGA reload app failed."
}

main $@
